module.exports = Motion;

var Point = require('./math/point')
  , Path = require('./path')
  , SubPath = require('./subpath')
  , utils = require('./utils')
  , config = require('../config');

/**
 * Realtime motion interface
 * This actually sends commands to the driver.
 * */
function Motion(ctx) {
  this.ctx = ctx;
  this.position = new Point(0, 0, 0);
  this.position.a = 0;
  this.speedMax = 0;
  this.speed = 0 ;
  this.currentSpeed = this.speed;
  this.previewMode = false;
  this.feed = 0;
  this.optimizeParams = {
    useOptimize: false
  };

  this.onLightDelay = 90; // 默认开光延迟
  this.offLightDelay = 190; // 默认关光延迟
  this.jumpDelay = 300; // 默认跳转延迟
  this.cornerDelay = 80; // 默认拐角延迟
  // if (this.optimizeParams.useOptimize) {
  //   this.onLightDelay = -220; // 默认开光延迟
  //   this.offLightDelay = 0; // 默认关光延迟
  // }
  
  this.lineToVector = {x: 0, y: 0, z: 0, a: 0}; // 初始G1向量
  this.lastLineTo = false; // 记录上一条指令是 lineTo 还是 moveTo， 
  // this.cosAngleLimit = this.optimizeParams && this.optimizeParams.limitAngle ? 
  //                      Math.cos(this.optimizeParams.limitAngle * Math.PI / 180) : -1.1;
  // this.lineLength = 0; // 记录当前路径长度

  // this.offset = {
  //   x : 0,
  //   y : 0,
  //   a : 0
  // }
  this.rotateParams = {
    enable: false,
    aAxisStepAngle: 0, // a轴步进角度
    yAxisStepLength: 0, // y轴步进距离
    xAxisStepLength: 0, // x轴步进距离
  }
}

Motion.prototype = {
  initDriver : function() {
    this.ctx.driver.init();
    this.ctx.driver.feed(this.feed);
    this.ctx.driver.freq();
    this.ctx.driver.onLightDelay(this.onLightDelay);
    this.ctx.driver.offLightDelay(this.offLightDelay);
    this.ctx.driver.jumpDelay(this.jumpDelay);
    this.ctx.driver.cornerDelay(this.cornerDelay);
    this.ctx.driver.version(config.version); 
  }
  , setSpeedMax: function (speedMax) { // 设置激光头功率的最大值
    this.speedMax = speedMax;
  }
  , setFeed: function (feed) { // 设置进给率( tcp 点速度)
    this.feed = feed;
    // this.setOptimizeParams({// TODO：临时版本暂时不开启优化
    //   useOptimize: false});
  }  
  , setOptimizeParams: function (params = {}) { // 设置优化参数
    this.optimizeParams = Object.assign(this.optimizeParams, params);
    let k1= 0.01; 
    let k2 = 0.012;
    let b1 = 0;
    let b2 = 0;
    if (this.feed < 120001){
      b1 = 0.02;
      b2 = 0.02;
    }
    
    this.accDistance = params.accDistance || 0; // 加速距离
    this.decDistance = params.decDistance || 0; // 减速距离
    // this.accDistance = this.feed * this.optimizeParams.accTime * 0.000001 * 2 * k1 + b1; // 加速距离
    // this.decDistance = this.feed * this.optimizeParams.decTime * 0.000001 * 2 * k2 + b2; // 减速距离    

    // 速度8000时，算法乘以40，fpga获取后除以60，实际速度 8000 * 0.66666 =  5333.3 mm/s, fpga 一个指令 10 us, 最小步长 0.053 微米
    // this.minLineLength =  params.minLength || this.feed * 0.6666 * 0.00001;; 
    this.minLineLength =  params.minLength || 0.05;; 
    this.limitLengthlinshi = this.linshibeishu * this.minLineLength; // 线段长度限制
    
    if (this.previewMode || !this.optimizeParams.useOptimize) {
      this.accDistance = 0;
      this.decDistance = 0;
    } 
    // else {
    //   this.onLightDelay = -220; // 默认开光延迟
    //   this.offLightDelay = 0; // 默认关光延迟
    // }
    // this.onLightDelay = params.onLightDelay || this.onLightDelay; // 默认开光延迟
    // this.offLightDelay = params.offLightDelay || this.offLightDelay; // 默认关光延迟
    // this.jumpDelay = params.jumpDelay || this.jumpDelay; // 默认跳转延迟
    // this.cornerDelay = params.cornerDelay || this.cornerDelay; // 默认拐角延迟

    this.onLightDelay = params.onLightDelay; // 默认开光延迟
    this.offLightDelay = params.offLightDelay; // 默认关光延迟
    this.jumpDelay = params.jumpDelay; // 默认跳转延迟
    this.cornerDelay = params.cornerDelay; // 默认拐角延迟
  }
  , setRotateMotion: function (params) { // 设置旋转参数
    this.rotateParams = Object.assign(this.rotateParams, params);
  }
  , laserOn: function () { // 表示激光头打开的动作。
    this.ctx.driver.laserOn.call(this.ctx.driver);
  }
  , laserOff: function () { // 表示激光头关闭的动作。
    this.ctx.driver.laserOff.call(this.ctx.driver);
  }
  , laserPower: function (power) { // 表示激光功率的设置。
    this.ctx.driver.speed.call(this.ctx.driver, power);
  }
  , laserPowerOff: function () {
    this.laserPower(0);
  }
  , laserPowerMax: function () {
    this.laserPower(this.speedMax);
  }
  , setPreviewMode: function (mode) {
    this.previewMode = mode;
    this.ctx.driver.setPreviewMode.call(this.ctx.driver, mode);
  }
  , finishProgram: function () { // 表示结束程序的动作。
    if (!this.previewMode && !this.rotateParams.enable) {
      if (this.optimizeParams.useOptimize) {
        this.rapid({x: 0, y: 0}); // 避免最后一段没进行关光延迟优化
      }      
      this.ctx.driver.laserOff.call(this.ctx.driver); // M5
      this.ctx.driver.rapid.call(this.ctx.driver, {x: 0, y: 0}); // G0X0Y0
    } else if (this.previewMode && this.rotateParams.enable && (this.rotateParams.previewMode !== 3) ) {
      this.ctx.driver.rapid.call(this.ctx.driver, {y: 0, a: 0}); // G0X0A0，旋转模式自动对调 xy轴
    }
    this.ctx.driver.finishProgram.call(this.ctx.driver);// M2
  }

  // , laserPower: function(power) { // 表示激光功率的设置。
  //     this.ctx.driver.laserPower.call(this.ctx.driver, power);
  //   }
  // , setOffset : function(offset) { // 设置偏移量
  //     this.offset = offset;
  // }
  , zero: function (params) {
    this.ctx.driver.zero.call(this.ctx.driver, params);
  }
  , rapid: function (params) {
    var newPosition = this.postProcess(params);
    if (!newPosition) return;

    // if (params.x !== undefined){
    //   params.x += this.offset.x;
    // }
    // if (params.y !== undefined){
    //   params.y += this.offset.y;
    // }
    // if (params.a !== undefined){
    //   params.a += this.offset.a;
    // }
    if(this.lastLineTo && !this.previewMode && this.optimizeParams.useOptimize){ // 开光延时优化: 关光会提前，导致线段没走完就关光了
      let p1 = this.extendVector(this.position, this.lineToVector, this.decDistance);
      this.laserPowerOff();
      this.ctx.driver.linear.call(this.ctx.driver, {x: p1.x, y: p1.y});
      this.ctx.driver.rapid.call(this.ctx.driver, params);
    }else{
      if (this.lastLineTo && !this.previewMode) this.laserPowerOff(); // 关光
      this.ctx.driver.rapid.call(this.ctx.driver, params);
    }

    this.lastLineTo = false;
    this.position = newPosition;
  }
  , linear: function (params) {
    var newPosition = this.postProcess(params);
    if (!newPosition) return;
    let newLineToVector = {
      x : newPosition.x - this.position.x,
      y : newPosition.y - this.position.y,
      z : newPosition.z - this.position.z,
      a : newPosition.a - this.position.a
    };

    // TODO: 将这里移出去
    let op = this.optimizeParams;
    let negLTV = {
      x : -this.lineToVector.x,
      y : -this.lineToVector.y,
      z : -this.lineToVector.z,
      a : -this.lineToVector.a
    };

    let useOptimize = this.isInAngleLimit(negLTV, newLineToVector);
    // let useOptimize = this.isInAngleLimit(negLTV, newLineToVector, this.cosAngleLimit);
    

    // TODO： 在这里判断是否要做拐角优化
    if (op && op.useOptimize && useOptimize &&
        op.limitAngle && !this.previewMode && this.lastLineTo) {
      // 新建 params 调用 moveto

      let p1 = this.extendVector(this.position, this.lineToVector, this.decDistance);
      // let p2 = this.extendVector(this.position, negLTV, this.accDistance);
      let p2 = this.extendVector(this.position, newLineToVector, -this.accDistance);
      
      // 如果这里用 motion 指令，会导致开光光延迟的参数对拐角优化无效
      this.laserPowerOff();
      this.ctx.driver.linear.call(this.ctx.driver, {x: p1.x, y: p1.y});
      this.ctx.driver.rapid.call(this.ctx.driver, {x: p2.x, y: p2.y});
      this.laserPowerMax();
      // this.ctx.driver.linear.call(this.ctx.driver, {x: this.position.x, y: this.position.y});
      this.ctx.driver.linear.call(this.ctx.driver, params);
      // 如果p1p2 存在
    } else if(!this.lastLineTo && !this.previewMode && op.useOptimize){// 开光延时优化: 尽量在匀速段开光，而不是加速段
      // 先后退至加速距离前
      let p1 = this.extendVector(this.position, newLineToVector, -this.accDistance);
      this.laserPowerOff(); // 关光
      this.ctx.driver.rapid.call(this.ctx.driver, {x: p1.x, y: p1.y}); // 先移到加速距离前
      this.laserPowerMax(); // 开光
      this.ctx.driver.linear.call(this.ctx.driver, params); // 直线
    } else if(!this.previewMode){
      if(!this.lastLineTo) this.laserPowerMax();  // 上一条是moveTo 先开光
      this.ctx.driver.linear.call(this.ctx.driver, params);
    } else if(this.previewMode){
      this.ctx.driver.linear.call(this.ctx.driver, params); // 20250606: 预览模式下使用 G1 指令
      // this.ctx.driver.rapid.call(this.ctx.driver, params); // 预览模式下没有 G1 指令
    }
    
    this.lastLineTo = true; // 预览模式先不管
    this.lineToVector = newLineToVector;
    this.position = newPosition;
  }
  , arcCW: function (params) {
    return this.arc(params, false);
  }
  , arcCCW: function (params) {
    return this.arc(params, true);
  }
  // 圆弧插补
  , arc: function (params, ccw) {
    var newPosition = this.postProcess(params);
    // 如果位置相同，有可能是个圆
    var cx = this.position.x + params.i;
    var cy = this.position.y + params.j;
    var arc = utils.pointsToArc({
      x: cx,
      y: cy
    },
      this.position, {
      x: params.x,
      y: params.y
    });

    var length = arc.radius * (arc.end - arc.start);
    var f = length / (1 / this.ctx.feed);
    f = Math.round(f * 1000000) / 1000000;
    if (f) params.f = Math.abs(f);


    if (!ccw && this.ctx.driver.arcCW) {
      this.ctx.driver.arcCW.call(this.ctx.driver, params);
    }
    else if (ccw && this.ctx.driver.arcCCW) {
      this.ctx.driver.arcCCW.call(this.ctx.driver, params);
    }
    else {
      this.interpolate('arc', [
        cx,
        cy,
        arc.radius,
        arc.start,
        arc.end,
        ccw],
        params.z || 0);
    }

    if (newPosition) {
      this.position = newPosition;
    }
  }
  // 直线和圆弧插补前的参数预处理
  , postProcess: function (params) {
    // 同步单位
    if (this.ctx.driver.unit && this.ctx.unit != this.currentUnit) {
      this.ctx.driver.unit(this.ctx.unit);
      this.currentUnit = this.ctx.unit;
    }

    // 同步工具直径
    if (this.ctx.driver.meta
      && this.ctx.toolDiameter != this.currentToolDiameter) {
      // 将 toolDiameter 在 gcode 代码上显示
      // this.ctx.driver.meta({
      //   tooldiameter: this.ctx.toolDiameter
      // });
      this.currentToolDiameter = this.ctx.toolDiameter;
    }

    // 设置新的主轴自动换刀（ATC）变化
    if (this.ctx.driver.atc
      && this.ctx.atc != this.currentAtc) {
      this.ctx.driver.atc(this.ctx.atc);
      this.currentAtc = this.ctx.atc;
    }

    // 设置新的主轴转速变化，在激光雕刻就是激光头的功率值
    // 预览模式下不设置主轴转速
    if (this.ctx.driver.speed
      && this.ctx.speed != this.currentSpeed
      && !this.previewMode) {
      this.ctx.driver.speed(this.ctx.speed);
      this.currentSpeed = this.ctx.speed;
    }

    // 新的进给率
    if (this.ctx.driver.feed
      && this.ctx.feed != this.currentFeed) {
      // this.ctx.driver.send('G93');
      this.currentFeed = this.ctx.feed;
    }

    // 冷却液
    // if (this.ctx.driver.coolant
    //   && this.ctx.coolant != this.currentCoolant) {
    //   this.ctx.driver.coolant(this.ctx.coolant);
    //   this.currentCoolant = this.ctx.coolant;
    // }



    // var dist = Point.distance(v1, this.position);
    // var v2 = this.position;
    // var dist = Math.sqrt(
    //   Math.pow(v2.x - v1.x, 2) +
    //   Math.pow(v2.y - v1.y, 2) +
    //   Math.pow(v2.z - v1.z, 2));

    // 更新速度
    // if (!params.f) {
    //   var f = dist / (1 / this.ctx.feed);
    //   f = Math.round(f * 1000000) / 1000000; // 保留小数点后6位。
    //   if (f) params.f = Math.abs(f); // 非 0 则更新速度参数
    // }



    // 更新参数值
    this.ctx.filters.forEach(function (f) {
      var tmp = f.call(this.ctx, params);

      if (tmp) {
        for (var k in tmp) {
          params[k] = tmp[k];
        }
      }
    });

    // 保留小数点后 3 位。
    for (var k in params) {
      if (typeof params[k] === 'number'){
        // params[k] = Math.round(params[k] * 100000) / 100000;
        params[k] = utils.fomatFloat(params[k], 3);
      }
    }
    // 根据 params 创建新的位置对象
    var v1 = new Point(
      params.x === undefined ? this.position.x : params.x
      , params.y === undefined ? this.position.y : params.y
      , params.z === undefined ? this.position.z : params.z
      , params.a === undefined ? this.position.a : params.a
    );

    // if((params.x !== undefined && utils.sameFloat(params.x, this.position.x)) ||
    //    (params.y !== undefined && utils.sameFloat(params.y, this.position.y)) ||
    //    (params.z !== undefined && utils.sameFloat(params.z, this.position.z)) ||
    //    (params.a !== undefined && utils.sameFloat(params.a, this.position.a))) {
      
    // } else {
    //   return false;
    // }
    if (utils.samePos(this.position, v1)) {
      return false;
    }

    return v1;
  }

  // 曲线插补
  , interpolate: function (name, args, zEnd) {
    var path = new SubPath();
    path[name].apply(path, args);

    var curLen = 0; // 当前长度
    var totalLen = path.getLength(); // 路径长度
    // var zStart = this.position.z;

    // 位置比例计算 z 轴
    // function helix() {
    //   var fullDelta = zEnd - zStart;
    //   var ratio = (curLen / totalLen);
    //   var curDelta = fullDelta * ratio;
    //   return zStart + curDelta;
    // }

    var pts = path.getPoints(30);
    for (var i = 0, l = pts.length; i < l; ++i) {
      var p = pts[i];

      // var xo = p.x - this.position.x;
      // var yo = p.y - this.position.y;
      // curLen += Math.sqrt(xo * xo + yo * yo);

      // this.linear({ x: p.x, y: p.y, z: helix() });
      this.linear({ x: p.x, y: p.y});
    }
  }

  // 执行 Path 上的动作序列
  , followPath: function (path, speed) {
    if (!path) return false;

    if (path.subPaths) { // 递归直到最里层的子路径
      // 递归调用 followPath 处理子路径
      path.subPaths.forEach(function (subPath) {
        this.followPath(subPath, speed);
      }, this);
      return;
    }

    if(this.optimizeParams.useOptimize){
      this.optimizePath(path); // 优化子路径
    }
    // var curLen = 0;
    var each = {};
    var motion = this;
    var driver = this.ctx.driver;
    var ctx = this.ctx;

    // 平面插补
    function interpolate(name, args) {
      var path = new SubPath();
      path.moveTo(motion.position.x, motion.position.y);
      path[name].apply(path, args);

      var pts;
      // if (motion.feed >= 40000){ // 速度大于 1000时
        let totalLen = path.getLength();
        let numaaa = Math.floor(totalLen / motion.minLineLength);
        numaaa = numaaa > 1000 ? 1000 : numaaa;
        pts = path.getPoints(numaaa);
      // }else{
      //   pts = path.getPoints(30);
      // }

      motion.optimizePointsPath(pts);

      for (var i = 0, l = pts.length; i < l; ++i) {
        var p = pts[i];
        // motion.linear({ x: p.x, y: p.y });

        let params = {};
        if (!utils.sameFloat(p.x, motion.position.x)) params.x = p.x;
        if (!utils.sameFloat(p.y, motion.position.y)) params.y = p.y;
        motion.linear(params);
      }
    }

    // 快速移动
    each[Path.actions.MOVE_TO] = function (x, y) {
      // motion.laserPowerOff(); // 将激光头关掉，准备移动
      if (this.previewMode) {
        motion.rapid({ x: x, y: y }); // 预览模式下一次性移动
      }else {
        let params = {};
        if (!utils.sameFloat(x, motion.position.x)) params.x = x;
        if (!utils.sameFloat(y, motion.position.y)) params.y = y;
        motion.rapid(params); // 快速移动
        // if (!utils.sameFloat(x, this.position.x)) motion.rapid({ x: x}); // 快速移动时如果 x 和 y 同时运动可能会出现走不准
        // if (!utils.sameFloat(y, this.position.y)) motion.rapid({ y: y});
        // motion.laserPowerMax(); // 快速移动完成，将激光头打开准备开始打标
      }
    };
    // 直线
    each[Path.actions.LINE_TO] = function (x, y) {

      // TODO: 求线段夹角，

      //       
      // var xo = p.x - this.position.x;
      // var yo = p.y - this.position.y;
      // curLen += Math.sqrt(xo * xo + yo * yo);


      let params = {};
      if (!utils.sameFloat(x, this.position.x)) params.x = x;
      if (!utils.sameFloat(y, this.position.y)) params.y = y;
      motion.linear(params);
    };
    // 椭圆弧
    each[Path.actions.ELLIPSE] = function (x, y, rx, ry,
      aStart, aEnd, ccw) {
      // 平面圆弧
      if (utils.sameFloat(rx, ry)) {
        var points = utils.arcToPoints(x, y,
          aStart,
          aEnd,
          rx);
        var params = {
          x: points.end.x, y: points.end.y,
          i: x - points.start.x, j: y - points.start.y
        };
        motion.arc(params, ccw);
      }
      else {
        interpolate('ellipse', arguments, mx, my);
      }
    };
    // 贝塞尔曲线
    each[Path.actions.BEZIER_CURVE_TO] = function () {
      interpolate('bezierCurveTo', arguments);
    };
    // 二次曲线
    each[Path.actions.QUADRATIC_CURVE_TO] = function () {
      interpolate('quadraticCurveTo', arguments);
    };

    // 遍历执行动作序列
    for (var i = 0, l = path.actions.length; i < l; ++i) {
      item = path.actions[i]

      // if (i != 0) {
      //   var x0 = this.position.x;
      //   var y0 = this.position.y;
      //   curLen += path.getActionLength(x0, y0, i);
      // }

      each[item.action].apply(this, item.args);
    }
  }

  // 旋转模式 x 轴用 a 坐标表示
  , followPathRotate: function (path, speed) {
    if (!path) return false;

    if (path.subPaths) { // 递归直到最里层的子路径
      // 递归调用 followPath 处理子路径
      path.subPaths.forEach(function (subPath) {
        this.followPathRotate(subPath, speed);
      }, this);
      return;
    }

    // this.optimizePath(path); // 优化子路径

    // var curLen = 0;
    var each = {};
    var motion = this;
    var driver = this.ctx.driver;
    var ctx = this.ctx;

    // 快速移动
    each[Path.actions.MOVE_TO] = function (x, y) {
      // motion.laserPowerOff(); // 将激光头关掉，准备移动
      if (this.previewMode) {
        let aLength = this.rotateParams.aAxisStepAngle * x  / this.rotateParams.xAxisStepLength - this.position.a;
        if (aLength > 540 || aLength < -540){// 超过角度限制
          let limit = aLength > 0 ? 540 : -540;
          let times = aLength / limit;
          for (let i = 0; i< times; i++){
            motion.rapid({a: this.position.a + limit})
          }
        }
        motion.rapid({ 
        a: this.rotateParams.aAxisStepAngle * x / this.rotateParams.xAxisStepLength, 
        y: y }); // 预览模式下一次性移动
      }else {
        let params = {};
        if (!utils.sameFloat(x, motion.position.x)) {
          params.a = this.rotateParams.aAxisStepAngle * x / this.rotateParams.xAxisStepLength;
        }
        if (!utils.sameFloat(y, motion.position.y)) params.y = y;
        motion.rapid(params); // 快速移动
      }
    };
    // 直线
    each[Path.actions.LINE_TO] = function (x, y) {
      let params = {};
      if (!utils.sameFloat(y, this.position.y)) params.y = y;
      let a = this.rotateParams.aAxisStepAngle * x / this.rotateParams.xAxisStepLength;
      if (!utils.sameFloat(a, this.position.a)) {
        params.a = a;
      } 
      let aLength = this.rotateParams.aAxisStepAngle * x  / this.rotateParams.xAxisStepLength - this.position.a;
      if (aLength > 540 || aLength < -540){// 超过角度限制
        let limit = aLength > 0 ? 540 : -540;
        let times = aLength / limit;
        for (let i = 0; i< times; i++){
          motion.linear({a: this.position.a + limit})
        }
      }
      motion.linear(params);
    };

    // 遍历执行动作序列
    for (var i = 0, l = path.actions.length; i < l; ++i) {
      item = path.actions[i]
      each[item.action].apply(this, item.args);
    }
  }

  // , isInAngleLimit: function (v1, v2, angleLimit = 90) {
  //   let ret = false;
  //   let angle = Math.acos((v1.x * v2.x + v1.y * v2.y) / (Math.sqrt(v1.x * v1.x + v1.y * v1.y) * Math.sqrt(v2.x * v2.x + v2.y * v2.y)));
  //   angle = angle * 180 / Math.PI;
  //   let cosAngleLimit = this.cosAngleLimit || Math.cos(angleLimit * Math.PI / 180);
  //   let dotProductSquare = (v1.x * v2.x + v1.y * v2.y) * (v1.x * v2.x + v1.y * v2.y);
  //   let projectionLength = cosAngleLimit * cosAngleLimit * (v1.x * v1.x + v1.y * v1.y) * (v2.x * v2.x + v2.y * v2.y);
  //   if (dotProductSquare < projectionLength) { // 夹角在限制范围内
  //     ret = true;
  //   }
  //   return ret;
  // }

  , isInAngleLimit: function (v1, v2) {
    let ret = false;
    let angleLimit = this.optimizeParams.limitAngle || 91;
    let angle = Math.acos((v1.x * v2.x + v1.y * v2.y) / (Math.sqrt(v1.x * v1.x + v1.y * v1.y) * Math.sqrt(v2.x * v2.x + v2.y * v2.y)));
    angle = angle * 180 / Math.PI;
    if (angle < angleLimit) { // 夹角在限制范围内
      ret = true;
    }
    return ret;
  }
    

  , extendVector:function (p, v, length) {
    let magnitude = Math.sqrt(v.x * v.x + v.y * v.y);
    if (magnitude < 0.001) {
      console.log('无法延伸零向量')
      return {
        x : p.x,
        y : p.y
      };
    }
    let scale = length / magnitude; // 计算缩放因子
    // ret.x /= magnitude; // 计算单位向量
    // ret.y /= magnitude;
    // ret.x *= length; // 计算延伸后的向量
    // ret.y *= length;
    return {
      x: p.x + v.x * scale,
      y: p.y + v.y * scale
    }
  }

  // 优化路径： 合并在同一矢量的路径，并确保每条路径的长度都大于 minLineLength
  , optimizePath: function (path) {
    if (!path) return false;

    let curPos = {x: 0, y: 0};
    let newPos = {x: 0, y: 0};
    let curVec = {x: 0, y: 0};
    let newVec = {x: 0, y: 0};
    let lastLineTo = false; // 标志上一条路径是不是加工路径

    for (let i = 0; i < path.actions.length; i++) {
      if (path.actions[i].action == Path.actions.MOVE_TO) { // 起点
        curPos = {x: path.actions[i].args[0], y: path.actions[i].args[1]};
        newPos = {x: path.actions[i].args[0], y: path.actions[i].args[1]};
        curVec = {x: 0, y: 0};
        newVec = {x: 0, y: 0};
        lastLineTo = false;
      } else if (path.actions[i].action == Path.actions.LINE_TO) { // 微小直线段路径
        newPos = {x: path.actions[i].args[0], y: path.actions[i].args[1]};
        newVec = {
          x: newPos.x - curPos.x,
          y: newPos.y - curPos.y,
        };
        // 1. 第一段矢量线段： 由于开始段都会增加缓冲距离，所以这里不做优化
        if (!lastLineTo) { // 不是连续直线
          lastLineTo = true;
          curPos = newPos;
          curVec = newVec; 
          continue;
        }
        // 2. 判断是不是共线且同向的
        if(Math.abs(curVec.x * newVec.y - curVec.y * newVec.x) < 0.001){ // 共线判断
          if(curVec.x * newVec.x + curVec.y * newVec.y > 0){ // 同向判断
            // 合并路径：直接删掉上一行
            newVec = {x: curPos.x - path.actions[i - 2].args[0], y: curPos.y - path.actions[i - 2].args[1]};
            path.actions.splice(i - 1, 1);
            i--;
          } // 反向理论上会超过角度限制，不做优化
        }
        // 3. 判断长度是否大于 10us 能走的最小长度 minLineLength。小于该值会降速，导致打标效果深浅不一。
        let lineLength = Math.sqrt(Math.pow(newVec.x, 2) + Math.pow(newVec.y, 2));
        if (lineLength < this.minLineLength) {
          for(; i < path.actions.length;){
            if (i == path.actions.length - 1 || path.actions[i + 1].action != Path.actions.LINE_TO){ // 最后一段或下一段不是直线
              // 向前合并直线段： 删除上一行
              if (i == 1) break; // 纯粹一条小直线，不做优化
              newVec = {x: curPos.x - path.actions[i - 2].args[0], y: curPos.y - path.actions[i - 2].args[1]};
              path.actions.splice(i - 1, 1);
              i--;
              break;
            } else {
              // 3.1 向后合并直线段
              path.actions.splice(i, 1); // 删除当前行
              // 计算总长度
              newVec = {
                x: path.actions[i].args[0] - path.actions[i - 1].args[0],
                y: path.actions[i].args[1] - path.actions[i - 1].args[1]
              }
              lineLength = Math.sqrt(Math.pow(newVec.x, 2) + Math.pow(newVec.y, 2));
              if (lineLength > this.minLineLength) {
                break;
              }
            }
          }
        }

        // 4. TODO:拐角优化: actions里面暂时无法处理开关光指令，暂时不在这里做
        // newVec = {
        //   x: path.actions[i].args[0] - path.actions[i - 1].args[0],
        //   y: path.actions[i].args[1] - path.actions[i - 1].args[1]
        // };
        // curVec = {
        //   x: path.actions[i - 1].args[0] - path.actions[i - 2].args[0],
        //   y: path.actions[i - 1].args[1] - path.actions[i - 2].args[1]
        // };
        // newPos = {x: path.actions[i].args[0], y: path.actions[i].args[1]};
        // curPos = {x: path.actions[i - 1].args[0], y: path.actions[i - 1].args[1]};
        // let negLTV = {
        //   x : -curVec.x,
        //   y : -curVec.y
        // };

        // let op = this.optimizeParams;
        // let useOptimize = this.isInAngleLimit(negLTV, newVec);
        // if (op && op.useOptimize && useOptimize && op.limitAngle && !this.previewMode && lastLineTo) {
        //   let p1 = this.extendVector(curPos, curVec, this.decDistance);
        //   // let p2 = this.extendVector(this.position, negLTV, this.accDistance);
        //   let p2 = this.extendVector(curPos, newVec, -this.accDistance);
        //   // 如果这里用 motion 指令，会导致开光光延迟的参数对拐角优化无效
        // }
        lastLineTo = true;
        curPos = newPos;
        curVec = newVec;
      }else{ //TODO: 其他曲线指令的衔接
        lastLineTo = false;
      }  
    }
  }

  , optimizePointsPath: function (pts) {
    if (!pts) return false;

    let curPos = new Point(pts[0].x, pts[0].y);
    let newPos = new Point(0, 0);
    let curVec = {x: 0, y: 0};
    let newVec = {x: 0, y: 0};

    for (let i = 1; i < pts.length; i++) {
      newPos.x = pts[i].x;
      newPos.y = pts[i].y;
      newVec = {
        x: newPos.x - curPos.x,
        y: newPos.y - curPos.y,
      };
      // 1. 判断是否共线且同向
      if(Math.abs(curVec.x * newVec.y - curVec.y * newVec.x) < 0.001){ // 共线判断
        if(curVec.x * newVec.x + curVec.y * newVec.y > 0){ // 同向判断
          // 合并路径：直接删掉上一个中间点
          newVec = {x: curPos.x - pts[i - 2].x, y: curPos.y - pts[i - 2].y};
          pts.splice(i - 1, 1);
          i--; 
        }
      }
      // 2. 判断长度是否大于 10us 能走的最小长度 minLineLength。小于该值会降速，导致打标效果深浅不一。
      let lineLength = Math.sqrt(Math.pow(newVec.x, 2) + Math.pow(newVec.y, 2));
      if (lineLength < this.minLineLength) {
        for(; i < pts.length;){
          if (i == pts.length - 1){ // 最后一段或下一段不是直线
            if (i == 1) break;
            // 向前合并直线段： 删除上一个中间点
            newVec = {x: curPos.x - pts[i - 2].x, y: curPos.y - pts[i - 2].y};
            pts.splice(i - 1, 1);
            i--;
            break;
          } else {
            // 3.1 向后合并直线段
            pts.splice(i, 1); // 删除当前行
            // 计算总长度
            newVec = {
              x: pts[i].x - pts[i - 1].x,
              y: pts[i].y - pts[i - 1].y
            }
            lineLength = Math.sqrt(Math.pow(newVec.x, 2) + Math.pow(newVec.y, 2));
            if (lineLength > this.minLineLength) {
              break;
            }
          }
        }
      }
      curPos.x = newPos.x;
      curPos.y = newPos.y;
      curVec = newVec;
    }
  }
};
